using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Services;
using JigLibX.Physics;
using Utilities;
using SpaceBattle.Logic;
using SpaceBattle.Logic.SampleLevel;


namespace SpaceBattle
{

  public interface IAudioManager
  {
    void OnWarp();

    void OnNukeExplode();

    void OnPlasmaExplode();

    void OnNukeLaunch();

    void OnPlasmaShoot();

    void OnProjectileShoot();

    void OnLaserShoot();

    void OnLightningShoot();

    void OnShockwaveShoot();
  }


  public class AudioManager : CameraConsumer, IAudioManager
  {
    protected ArrayList<SoundEffectInstance> laser, machine_gun, lightning, shockwave;
    protected ArrayList<SoundEffectInstance> laser_expl;
    protected ArrayList<SoundEffectInstance> laser_shoot;
    protected ArrayList<SoundEffectInstance> nuke_launch;
    protected ArrayList<SoundEffectInstance> nuke_expl;
    protected ArrayList<SoundEffectInstance> warp;

    protected string laser_p, machine_gun_p, laser_expl_p, nuke_launch_p, nuke_expl_p, warp_p, lightning_path, laser_path, shockwave_p;

    public AudioManager(Microsoft.Xna.Framework.Game game)
      : base(game)
    {
      game.Services.AddService(typeof(IAudioManager), this);
      this.UpdateOrder = (int)ComponentOrders.SCENE;
      this.DrawOrder = (int)ComponentOrders.SCENE;
    }

    public override void Initialize()
    {
      var game = Game;

      laser_p = "Audio/laser_blast";
      machine_gun_p = "Audio/machine_gun";
      laser_expl_p = "Audio/laser_blast2";
      nuke_launch_p = "Audio/nuke_launch";
      nuke_expl_p = "Audio/bomb2";
      warp_p = "Audio/warp";
      lightning_path = "Audio/lightning";
      laser_path = "Audio/laser";
      shockwave_p = "Audio/shockwave";

      laser = new ArrayList<SoundEffectInstance>(15) { Game.Content.Load<SoundEffect>(laser_p).CreateInstance(), 
          Game.Content.Load<SoundEffect>(laser_p).CreateInstance(), Game.Content.Load<SoundEffect>(laser_p).CreateInstance(), 
          Game.Content.Load<SoundEffect>(laser_p).CreateInstance(), Game.Content.Load<SoundEffect>(laser_p).CreateInstance() };
      machine_gun = new ArrayList<SoundEffectInstance>(15) { Game.Content.Load<SoundEffect>(machine_gun_p).CreateInstance(), 
          Game.Content.Load<SoundEffect>(machine_gun_p).CreateInstance(), Game.Content.Load<SoundEffect>(machine_gun_p).CreateInstance(),
          Game.Content.Load<SoundEffect>(machine_gun_p).CreateInstance(), Game.Content.Load<SoundEffect>(machine_gun_p).CreateInstance()};
      laser_expl = new ArrayList<SoundEffectInstance>(15) { Game.Content.Load<SoundEffect>(laser_expl_p).CreateInstance(), 
          Game.Content.Load<SoundEffect>(laser_expl_p).CreateInstance(), Game.Content.Load<SoundEffect>(laser_expl_p).CreateInstance() };
      nuke_launch = new ArrayList<SoundEffectInstance>(15) { Game.Content.Load<SoundEffect>(nuke_launch_p).CreateInstance(), 
          Game.Content.Load<SoundEffect>(nuke_launch_p).CreateInstance(), Game.Content.Load<SoundEffect>(nuke_launch_p).CreateInstance(), Game.Content.Load<SoundEffect>(nuke_launch_p).CreateInstance() };
      nuke_expl = new ArrayList<SoundEffectInstance>(15) { Game.Content.Load<SoundEffect>(nuke_expl_p).CreateInstance(), 
          Game.Content.Load<SoundEffect>("Audio/bomb-01").CreateInstance(), Game.Content.Load<SoundEffect>("Audio/bomb-03").CreateInstance() };
      warp = new ArrayList<SoundEffectInstance>(15) { Game.Content.Load<SoundEffect>(warp_p).CreateInstance(), 
          Game.Content.Load<SoundEffect>(warp_p).CreateInstance(), Game.Content.Load<SoundEffect>(warp_p).CreateInstance(), 
          Game.Content.Load<SoundEffect>(warp_p).CreateInstance(), Game.Content.Load<SoundEffect>(warp_p).CreateInstance() };
      lightning = new ArrayList<SoundEffectInstance>(15) { Game.Content.Load<SoundEffect>(lightning_path).CreateInstance(), 
          Game.Content.Load<SoundEffect>(lightning_path).CreateInstance()};
      laser_shoot = new ArrayList<SoundEffectInstance>(15) { Game.Content.Load<SoundEffect>(laser_path).CreateInstance(), 
          Game.Content.Load<SoundEffect>(laser_path).CreateInstance(), Game.Content.Load<SoundEffect>(laser_path).CreateInstance() };
      shockwave = new ArrayList<SoundEffectInstance>(15) { Game.Content.Load<SoundEffect>(shockwave_p).CreateInstance(), 
          Game.Content.Load<SoundEffect>(shockwave_p).CreateInstance(), Game.Content.Load<SoundEffect>(shockwave_p).CreateInstance() };

      base.Initialize();
    }

    static private float volume;

    static public float Volume
    {
      get { return volume; }
      set { volume = value; MediaPlayer.Volume = volume; }
    }

    protected override void Dispose(bool disposing)
    {
      Game.Services.RemoveService(typeof(IAudioManager));
      base.Dispose(disposing);
    }

    public void OnWarp()
    {
        PlaySoundEffectInstance(warp, 0.0f, 0.0f, warp_p);
    }

    public void OnNukeExplode()
    {
        for (int i = 0; i < nuke_expl.Count; i++)
        {
            if (nuke_expl[i].State != SoundState.Playing)
            {
                nuke_expl[i].Pan = 0.0f;
                nuke_expl[i].Pitch = 0.0f;
                nuke_expl[i].Volume = AudioManager.Volume;
                nuke_expl[i].Play();
                return;
            }
        }
        //PlaySoundEffectInstance(nuke_expl, 0.0f, 0.0f, nuke_expl_p);
    }

    public void OnPlasmaExplode()
    {
        PlaySoundEffectInstance(laser_expl, 0.0f, 0.0f, laser_expl_p);
    }

    public void OnNukeLaunch()
    {
        PlaySoundEffectInstance(nuke_launch, 0.0f, 0.0f, nuke_launch_p);
    }

    public void OnPlasmaShoot()
    {
        PlaySoundEffectInstance(laser, 0.0f, 0.0f, laser_p);
    }

    public void OnProjectileShoot()
    {
        PlaySoundEffectInstance(machine_gun, 2.0f, 0, 0, machine_gun_p);
    }

    public void OnLightningShoot()
    {
        PlaySoundEffectInstance(lightning, 2.0f, 0, 0, lightning_path);
    }

    public void OnLaserShoot()
    {
        PlaySoundEffectInstance(laser_shoot, 3.0f, 0, 0, laser_path);
    }

    public void OnShockwaveShoot()
    {
        PlaySoundEffectInstance(shockwave, 0, 0, shockwave_p);
    }

    private void PlaySoundEffectInstance(ArrayList<SoundEffectInstance> effect_list, float pitch, float pan, string path)
    {
        for (int i = 0; i < effect_list.Count; i++)
        {
            if (!(effect_list[i].State == SoundState.Playing))
            {
                effect_list[i].Pitch = pitch;
                effect_list[i].Pitch = pan;
                effect_list[i].Volume = AudioManager.Volume;
                effect_list[i].Play();
                return;
            }
        }

        effect_list.Add(Game.Content.Load<SoundEffect>(path).CreateInstance());
        PlaySoundEffectInstance(effect_list, pitch, pan, path);
    }

    private void PlaySoundEffectInstance(ArrayList<SoundEffectInstance> effect_list, float volume_div, float pitch, float pan, string path)
    {
        for (int i = 0; i < effect_list.Count; i++)
        {
            if (!(effect_list[i].State == SoundState.Playing))
            {
                effect_list[i].Pitch = pitch;
                effect_list[i].Pitch = pan;
                effect_list[i].Volume = AudioManager.Volume / volume_div;
                effect_list[i].Play();
                return;
            }
        }

        effect_list.Add(Game.Content.Load<SoundEffect>(path).CreateInstance());
        PlaySoundEffectInstance(effect_list, volume_div, pitch, pan, path);
    }
  }
}